﻿using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using OS.Infrastructure.Domain;

namespace TaskKernel.Domain
{
    [DataContract]
    public class Department : AbstractEntity
    {
        protected IList<Task> tasks;
        protected ICollection<DepartmentUser> usersWithRole;

        public Department()
        {
            usersWithRole = new HashSet<DepartmentUser>();
            tasks = new List<Task>();
        }

        public Department(string virtualpath)
            : this()
        {
            WebPath = virtualpath;
        }

        public virtual bool IsClaim { get; set; }
        public virtual bool IsClaimNotify { get; set; }
        public virtual bool RatingRequired { get; set; }
        public virtual int Code { get; protected set; }

        [DataMember]
        public virtual string DepartmentName { get; set; }

        public virtual string WebPath { get; set; }
        public virtual string MailBox { get; set; }

        public virtual IEnumerable<Task> Tasks
        {
            get { return tasks; }
        }

        public virtual string Message { get; set; }

        public virtual IEnumerable<DepartmentUser> UsersWithRole
        {
            get { return usersWithRole; }
        }

        public virtual IEnumerable<Account> Executors
        {
            get
            {
                return usersWithRole.Where(x => x.Role == RoleEnum.Executor || x.Role == RoleEnum.Admin).Select(z => z.User).
                    OrderBy(z => z.FullName).ToList();
            }
        }

        public virtual IEnumerable<Account> Admins
        {
            get
            {
                return usersWithRole.Where(x => x.Role == RoleEnum.Admin).Select(z => z.User).
                    OrderBy(z => z.FullName).ToList();
            }
        }

        public virtual IEnumerable<Account> Participants
        {
            get
            {
                return
                    usersWithRole.Where(x => x.Role == RoleEnum.Participant).Select(z => z.User).
                        OrderBy(z => z.FullName).ToList();
            }
        }

      

        public virtual void SetMailBox(string eMail)
        {
            MailBox = eMail;
        }

        public virtual RoleEnum GetRole(Account account)
        {
            var roles =  usersWithRole.Where(x => x.User.UID == account.UID).Select(z => z.Role);
            if (roles.Any()){
                if (roles.Contains(RoleEnum.AdminWithoutMessage))
                    return RoleEnum.AdminWithoutMessage;
                if (roles.Contains(RoleEnum.Admin))
                    return RoleEnum.Admin;
                if (roles.Contains(RoleEnum.Executor))
                    return RoleEnum.Executor;
            }
            return RoleEnum.Other;

        }

        public virtual bool CreateUserRole(Account account, RoleEnum role)
        {
            usersWithRole.Add(new DepartmentUser(this, account, role));
            return true;
        }

        public virtual bool DeleteUserRole(DepartmentUser userRole)
        {
            if (CheckRemoveRole(userRole))
                return usersWithRole.Remove(userRole);
            return false;
        }

        public virtual bool ChangeUserRole(DepartmentUser userRole, DepartmentUser newRole)
        {
            if (CheckChangeRole(userRole, newRole))
            {
                if (usersWithRole.Remove(userRole))
                {
                    userRole.Role = newRole.Role;
                    usersWithRole.Add(userRole);
                    return true;
                }
            }
            return false;
        }

        private bool CheckRemoveRole(DepartmentUser userWithRole)
        {
            if (userWithRole.IsAdminOrExecutor)
            {
                if (HasTasksInProgressWithExecutor(userWithRole.User))
                {
                    Message =
                        "Нельзя удалить исполнителя или администратора, если у пользователя есть задачи";
                    return false;
                }
            }
            return true;
        }

        private bool CheckChangeRole(DepartmentUser userWithRole, DepartmentUser user)
        {
            if (userWithRole.IsAdminOrExecutor && user.IsParticipantDepartment)
            {
                if (HasTasksInProgressWithExecutor(userWithRole.User))
                {
                    Message =
                        "Нельзя сменить роль с администратора или исполнителя на авт. участника, если у пользователя есть задачи";
                    return false;
                }
            }
            return true;
        }

        private bool HasTasksInProgressWithExecutor(Account account)
        {
            IEnumerable<Task> tasks = Tasks.Where(x => x.InProgress());
            return tasks.Any(x => x.Executor.Equals(account));
        }
    }
}